package ant;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;


/**
 * Mais informações em
 * <i>http://www.coderanch.com/how-to/java/AntTask</i><br>
 * <i>http://ant.apache.org/manual/tutorial-writing-tasks.html</i>
 * 
 */
public class CriaCenario extends Task {
	
	private String diretorioBase;

	private String arquivoBase;
	
	private String diretorio;
	
	private int arquivos;
	
	private ArrayList<String> atributosSimples;
	
	private ArrayList<String> atributosMultiplos;
	
	private HashMap<String, String[]> mapa = new HashMap<String, String[]>();
	
    // called to initialize the task
    @Override
    public void init() throws BuildException {
    	super.init();
    	
    	arquivos = 1;
    	
    	atributosSimples = new ArrayList<String>();
    	
    	atributosMultiplos = new ArrayList<String>();
    }
    
    // called to execute the task
    @Override
    public void execute() throws BuildException {
    	    	
    	String arquivo = lerConteudoArquivo();
    	log("Arquivo base foi lido.");
    	
    	for (String key : mapa.keySet()) {
    		if (mapa.get(key).length == 1) {
    			atributosSimples.add(key);
    		}
    		else {
    			atributosMultiplos.add(key);
    		}
    	}
    	
    	String conteudo = arquivo;
    	
    	if (!atributosSimples.isEmpty()) {
    		conteudo = construirConteudoSimples(arquivo, atributosSimples.toArray(new String[atributosSimples.size()]), mapa);
    	}
    	
    	if (atributosMultiplos.isEmpty()) {
    		criarArquivo(conteudo);
    	}
    	else {
    		construirConteudoMultiplo(conteudo, atributosMultiplos.toArray(new String[atributosMultiplos.size()]), 0, mapa);
    	}
		
    	
    }
    
    private String lerConteudoArquivo() {
    	FileReader fileReader;
    	
    	try {
			fileReader = new FileReader(diretorioBase + "/" + arquivoBase);
			log("Lendo dados do aqruivo " + diretorioBase + "/" + arquivoBase);
		}
    	catch (FileNotFoundException e) {
			throw new BuildException(e.getMessage());
		}
    	
    	BufferedReader bufferedReader = new BufferedReader(fileReader);
    	
    	String conteudoArquivo = "";
    	String conteudo;
    	
    	while (true) {
    		try {
    			conteudo = bufferedReader.readLine();
    			if (conteudo == null) {
    				break;
    			}
    			conteudoArquivo += conteudo + "\n";
			}
    		catch (IOException e) {
    			throw new BuildException(e.getMessage());
			}
    	}
    	
    	return conteudoArquivo;
    }
    
	private String[] recuperaValores(final String string) {
		
		if (string.contains("..")) {
			String[] strings = string.split("\\.\\.");
			
			String[] s = new String[3];
			s[0] = "*";
			s[1] = strings[0].trim();
			s[2] = strings[1].trim();

			return s;
		}
		
		if (!string.contains(",")) {
			return new String[]{ string };
		}
		
		String[] strings = string.split(",");
		
		for (int i = 0; i < strings.length; i++) {
			strings[i] = strings[i].trim();
		}
		
		return strings;
	}
    
	private String construirConteudoSimples(final String arquivo, final String[] atributos, final HashMap<String, String[]> mapa) {
		
		String conteudo = arquivo;
		
		for (String key : atributos) {
			conteudo = arquivo.replaceAll("@" + key + "@", mapa.get(key)[0]);
		}
				
		return conteudo;
	}
    
	private void construirConteudoMultiplo(final String arquivo, final String[] atributosMultiplos,
			final int proximoAtributo, final HashMap<String, String[]> mapa) {
		
		if (proximoAtributo >= atributosMultiplos.length) {
			criarArquivo(arquivo);
			return;
		}
		else {
			String atributo = atributosMultiplos[proximoAtributo];
			if (mapa.get(atributo).length == 0) {
				return;
			}
			
			if (mapa.get(atributo)[0].equals("*")) {
				int inicio = Integer.valueOf(mapa.get(atributo)[1]);
				int fim = Integer.valueOf(mapa.get(atributo)[2]);
				
				for (int i=inicio; i<=fim; i++) {
					String valor = String.valueOf(i);
					construirConteudoMultiplo(arquivo.replaceAll("@" + atributo + "@", valor), atributosMultiplos, proximoAtributo+1, mapa);
				}
			}
			else {
				int valorPos = 0;
				while (valorPos < mapa.get(atributo).length) {
					construirConteudoMultiplo(arquivo.replaceAll("@" + atributo + "@", mapa.get(atributo)[valorPos]), atributosMultiplos, proximoAtributo+1, mapa);
					valorPos++;
				}
			}
		}
	}
    
    private void criarArquivo(String arquivo) {
    	log("Preparando arquivo");
    	
    	String nomeArquivo = diretorio + "/" + arquivoBase + "." + arquivos++;
    	
		try {
			FileWriter fileWriter = new FileWriter(nomeArquivo);
			BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
			bufferedWriter.write(arquivo);
			bufferedWriter.close();
			log("Criando arquivo " + nomeArquivo);
		}
		catch (IOException e) {
			log(e.getMessage(), 1);
		}
		
    	
	}
    
	public void setDiretorioArquivoBase(String diretorioBase) {
		this.diretorioBase = diretorioBase;
	}

	public void setArquivoBase(String arquivoBase) {
		this.arquivoBase = arquivoBase;
	}
	
	public void setDiretorio(String diretorio) {
		this.diretorio = diretorio;
	}

	public void setDebug(String debug) {
		mapa.put("debug", recuperaValores(debug));
		//this.debug = debug;
	}

	public void setDebugConsole(String debugConsole) {
		mapa.put("debugConsole", recuperaValores(debugConsole));
		//this.debugConsole = debugConsole;
	}

	public void setPlotarGraficos(String plotarGraficos) {
		mapa.put("plotarGraficos", recuperaValores(plotarGraficos));
		//this.plotarGraficos = plotarGraficos;
	}

	public void setFaseTransienteMetrica(String faseTransienteMetrica) {
		mapa.put("faseTransienteMetrica", recuperaValores(faseTransienteMetrica));
		//this.faseTransienteMetrica = faseTransienteMetrica;
	}

	public void setFaseTransienteInclinacaoMinima(
			String faseTransienteInclinacaoMinima) {
		mapa.put("faseTransienteInclinacaoMinima", recuperaValores(faseTransienteInclinacaoMinima));
		//this.faseTransienteInclinacaoMinima = faseTransienteInclinacaoMinima;
	}

	public void setFaseTransienteTotalVerificacoes(
			String faseTransienteTotalVerificacoes) {
		mapa.put("faseTransienteTotalVerificacoes", recuperaValores(faseTransienteTotalVerificacoes));
		//this.faseTransienteTotalVerificacoes = faseTransienteTotalVerificacoes;
	}

	public void setColetasPorRodada(String coletasPorRodada) {
		mapa.put("coletasPorRodada", recuperaValores(coletasPorRodada));
		//this.coletasPorRodada = coletasPorRodada;
	}

	public void setBlocos(String blocos) {
		mapa.put("blocos", recuperaValores(blocos));
		//this.blocos = blocos;
	}
	
	public void setBlocosIniciaisSistema(String blocosIniciaisSistema) {
		mapa.put("blocosIniciaisSistema", recuperaValores(blocosIniciaisSistema));
		//this.blocosIniciaisSistema = blocosIniciaisSistema;
	}

	public void setPopulacaoInicial(String populacaoInicial) {
		mapa.put("populacaoInicial", recuperaValores(populacaoInicial));
		//this.populacaoInicial = populacaoInicial;
	}

	public void setRecomendacao(String recomendacao) {
		mapa.put("recomendacao", recuperaValores(recomendacao));
		//this.recomendacao = recomendacao;
	}

	public void setLambda(String lambda) {
		mapa.put("lambda", recuperaValores(lambda));
		//this.lambda = lambda;
	}

	public void setMi(String mi) {
		mapa.put("mi", recuperaValores(mi));
		//this.mi = mi;
	}

	public void setU(String u) {
		mapa.put("u", recuperaValores(u));
		//this.u = u;
	}

	public void setGama(String gama) {
		mapa.put("gama", recuperaValores(gama));
		//this.gama = gama;
	}

	public void setPoliticaSelecaoBlocos(String politicaSelecaoBlocos) {
		mapa.put("politicaSelecaoBlocos", recuperaValores(politicaSelecaoBlocos));
		//this.politicaSelecaoBlocos = politicaSelecaoBlocos;
	}

	public void setPoliticaSelecaoVizinhos(String politicaSelecaoVizinhos) {
		mapa.put("politicaSelecaoVizinhos", recuperaValores(politicaSelecaoVizinhos));
		//this.politicaSelecaoVizinhos = politicaSelecaoVizinhos;
	}
	
	public void setArquivoVazao(String arquivoVazao) {
		mapa.put("arquivoVazao", recuperaValores(arquivoVazao));
		//this.arquivoVazao = arquivoVazao;
	}

}
